package com.ruoyi.warning.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.ruoyi.common.core.base.Result;
import com.ruoyi.common.core.page.PageHik;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.warning.domain.entity.Camera;
import com.ruoyi.warning.domain.entity.CameraSetting;
import com.ruoyi.warning.domain.entity.Encode;
import com.ruoyi.warning.domain.http.Expressions;
import com.ruoyi.warning.domain.query.CameraQuery;
import com.ruoyi.warning.domain.query.EncodeQuery;
import com.ruoyi.warning.mapper.CameraMapper;
import com.ruoyi.warning.service.ICameraService;
import com.ruoyi.warning.service.ICameraSettingService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 海康监控表 服务实现类
 * </p>
 *
 * @author chenhc
 * @since 2025-05-21
 */
@Service
public class CameraServiceImpl extends ServiceImpl<CameraMapper, Camera> implements ICameraService {
    @Resource
    private ICameraSettingService cameraSettingService;

    @Override
    public Object getPage(CameraQuery query) {
        Page<Camera> page = PageHelper.startPage(query.getPageNum(),query.getPageSize());
        List<Camera> list = this.list(new QueryWrapper<Camera>().lambda()
                .like(query.getName()!=null,Camera::getName, query.getName())
                .eq(query.getSettingId()!=null,Camera::getSettingId, query.getSettingId())
                .eq(query.getOnlineStatus()!=null,Camera::getOnlineStatus, query.getOnlineStatus())
                .orderByAsc(Camera::getOnlineStatus,Camera::getIp,Camera::getChannelNo)
        );
        TableDataInfo tableDataInfo = new TableDataInfo(list, page.getTotal());
        return tableDataInfo;
    }

    @Override
    public void refresh(CameraQuery query) {
        JSONObject jsonBody = new JSONObject();
        jsonBody.put("pageNo", 1);
        jsonBody.put("pageSize", 500);
        if(ObjectUtils.isEmpty(query.getSettingId())){
            //刷新全部
            List<CameraSetting> cameraSettingList = cameraSettingService.list();
            if (ObjectUtils.isEmpty(cameraSettingList)){
                return;
            }
            for(CameraSetting setting : cameraSettingList){
                List<Camera> list = cameraList(setting,jsonBody);
                //分成多次，每次400条
                int batchSize = 400;
                List<Camera> allProcessedCameras = new ArrayList<>();
                for (int i = 0; i < list.size(); i += batchSize) {
                    int endIndex = Math.min(i + batchSize, list.size());
                    List<Camera> subList = list.subList(i, endIndex);
                    List<Camera> processedSubList = onlineStatusCheck(setting, subList);
                    allProcessedCameras.addAll(processedSubList);
                }
                this.saveOrUpdateBatch(allProcessedCameras);
            }
        }else {
            //刷新指定
            CameraSetting setting = cameraSettingService.getById(query.getSettingId());
            List<Camera> list = cameraList(setting,jsonBody);
            int batchSize = 400;
            List<Camera> allProcessedCameras = new ArrayList<>();
            for (int i = 0; i < list.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, list.size());
                List<Camera> subList = list.subList(i, endIndex);
                subList = onlineStatusCheck(setting, subList);
                allProcessedCameras.addAll(subList);
            }
            this.saveOrUpdateBatch(allProcessedCameras);
        }
    }

    @Override
    public List<Encode> refreshEncode(EncodeQuery query) {
        List<Encode> list = new ArrayList<>();
        if(ObjectUtils.isEmpty(query.getSettingId())){
            //刷新全部
            List<CameraSetting> cameraSettingList = cameraSettingService.list();
            if (ObjectUtils.isEmpty(cameraSettingList)){
                return null;
            }
            for(CameraSetting setting : cameraSettingList){
                list.addAll(getEncodeList(setting));
            }
        }else {
            //刷新指定
            CameraSetting setting = cameraSettingService.getById(query.getSettingId());
            list = getEncodeList(setting);
        }
        return list;
    }


    private List<Camera> onlineStatusCheck(CameraSetting setting,List<Camera> list) {
        String[] idArray = list.stream()
                .map(camera -> String.valueOf(camera.getIndexCode()))
                .collect(Collectors.toList())
                .toArray(new String[0]);
        String[] parentArray = list.stream()
                .map(camera -> String.valueOf(camera.getParentIndexCode()))
                .distinct()
                .collect(Collectors.toList())
                .toArray(new String[0]);
        System.out.println("+++++++++++++++++++++++++++++");
        for (String id : parentArray) {
            System.out.print(id + " ");
        }
        Map<String, Camera> onlineMap = getCameraOnline(setting,idArray);
        Map<String, Camera> encodeMap = getEncodeDevice(setting,parentArray);

        System.out.println("+++++++++++++++++++++++++++++");
        System.out.println("map结果示例: " + encodeMap);
        if(ObjectUtils.isEmpty(onlineMap)||ObjectUtils.isEmpty(encodeMap)){
            return list;
        }
        for (Camera camera : list) {
            // 缓存 map 查找结果，避免重复查找
            Camera onlineInfo = onlineMap.get(camera.getIndexCode());
            Camera encodeInfo = encodeMap.get(camera.getParentIndexCode());
            if (ObjectUtils.isNotEmpty(onlineInfo)) {
                camera.setOnlineStatus(onlineInfo.getOnlineStatus());
//                camera.setIp(onlineInfo.getIp());
//                camera.setPort(onlineInfo.getPort());
            }
            if (ObjectUtils.isNotEmpty(encodeInfo)) {
                camera.setIp(encodeInfo.getIp());
                camera.setPort(encodeInfo.getPort());
            }
        }

        return list;
    }

    public Map<String, Camera> getCameraOnline(CameraSetting setting,String[] ids) {
        JSONObject jsonBody = new JSONObject();
        jsonBody.put("indexCodes", ids);
        jsonBody.put("pageNo", 1);
        jsonBody.put("pageSize", 1000);
        Result result = hikRequest(setting,"/api/nms/v1/online/camera/get",jsonBody);
        PageHik pageHik = JSON.parseObject(result.getData().toString(), PageHik.class);
        Map<String, Camera> map = new HashMap<>();
        if(ObjectUtils.isEmpty(pageHik.getList())){
            return map;
        }
        for(Object o:pageHik.getList()){
            HashMap<String,Object> cameraMap = JSON.parseObject(o.toString(), HashMap.class);
            if(ObjectUtils.isEmpty(cameraMap)){
                continue;
            }
            Camera camera = new Camera();
            camera.setOnlineStatus(Objects.toString(cameraMap.get("online"),""));
            camera.setIp(Objects.toString(cameraMap.get("ip"),""));
            camera.setPort(Objects.toString(cameraMap.get("port"),""));
            map.put(cameraMap.get("indexCode").toString(),camera);
        }
        return map;
    }

    private Map<String, Camera> getEncodeDevice(CameraSetting setting,String[] ids) {
        Map<String, Camera> map = new HashMap<>();
        Expressions expressions = new Expressions("indexCode",3,null);
        JSONObject jsonBody = new JSONObject();
        for (int i = 0; i < ids.length; i += 20) {
            int endIndex = Math.min(i + 20, ids.length);
            String[] array = Arrays.copyOfRange(ids, i, endIndex);
            expressions.setValues(array);
            Object[] expressionsArray = new Object[]{expressions};
            jsonBody.put("expressions", expressionsArray);
        }
        jsonBody.put("pageNo", 1);
        jsonBody.put("pageSize", 1000);
        System.out.println("+++++++++++++++++++++++++++++");
        System.out.println("jsonBody结果示例: " + jsonBody);
        System.out.println(jsonBody);
        Result result = hikRequest(setting,"/api/resource/v2/encodeDevice/search",jsonBody);
        System.out.println("+++++++++++++++++++++++++++++");
        PageHik pageHik = JSON.parseObject(result.getData().toString(), PageHik.class);

        if(ObjectUtils.isEmpty(pageHik.getList())){
            return map;
        }
        for(Object o:pageHik.getList()){
            HashMap<String,Object> cameraMap = JSON.parseObject(o.toString(), HashMap.class);
            Camera camera = new Camera();
            camera.setIp(Objects.toString(cameraMap.get("ip"),""));
            camera.setPort(Objects.toString(cameraMap.get("port"),""));
            map.put(cameraMap.get("indexCode").toString(),camera);
        }
        return map;
    }

    public List<Camera> cameraList(CameraSetting setting,JSONObject jsonBody) {
        Result result = hikRequest(setting,"/api/resource/v2/camera/search",jsonBody);
        PageHik pageHik = JSON.parseObject(result.getData().toString(), PageHik.class);
        System.out.println(pageHik.getList());
        List<Camera> list = new ArrayList<>();
        for(Object obj : pageHik.getList()){
            Camera camera = JSON.parseObject(obj.toString(), Camera.class);
            camera.setSettingId(setting.getId());
            list.add(camera);
        }
        return list;
    }

    private List<Encode> getEncodeList(CameraSetting setting) {
        List<Encode> list = new ArrayList<>();
        JSONObject jsonBody = new JSONObject();
        jsonBody.put("pageNo", 1);
        jsonBody.put("pageSize", 1000);
        System.out.println("+++++++++++++++++++++++++++++");
        System.out.println("jsonBody结果示例: " + jsonBody);
        System.out.println(jsonBody);
        Result result = hikRequest(setting,"/api/resource/v2/encodeDevice/search",jsonBody);
        System.out.println("+++++++++++++++++++++++++++++");
        PageHik pageHik = JSON.parseObject(result.getData().toString(), PageHik.class);

        if(ObjectUtils.isEmpty(pageHik.getList())){
            return list;
        }
        for(Object o:pageHik.getList()){
            Encode encode = JSON.parseObject(o.toString(), Encode.class);
            encode.setSettingId(setting.getId());
            encode.setPort(null);
            list.add(encode);
        }
        return list;
    }


    //调用海康接口
    private Result hikRequest(CameraSetting setting,String url, JSONObject jsonBody){

        /**
         * STEP1：设置平台参数，根据实际情况,设置host appkey appsecret 三个参数.
         */
        ArtemisConfig.host = setting.getHostname(); // 平台的ip端口
        ArtemisConfig.appKey = setting.getAppKey();  // 密钥appkey
        ArtemisConfig.appSecret = setting.getAppSecret();// 密钥appSecret
        /**
         * STEP2：设置OpenAPI接口的上下文
         */
        final String ARTEMIS_PATH = "/artemis";
        /**
         * STEP3：设置接口的URI地址
         */
        final String previewURLsApi = ARTEMIS_PATH + url;
        Map<String, String> path = new HashMap<String, String>(2) {
            {
                put("https://", previewURLsApi);//根据现场环境部署确认是http还是https
            }
        };
        /**
         * STEP4：设置参数提交方式
         */
        String contentType = "application/json;charset=UTF-8";
        /**
         * STEP5：组装请求参数
         */
        String body = jsonBody.toJSONString();
        /**
         * STEP6：调用接口
         */
        String jsonString = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType , null);// post请求application/json类型参数
        System.out.println(body);
        System.out.println(jsonString);
        Result r = null;
        if(jsonString!=null){
            r=  JSON.parseObject(jsonString, Result.class);
        }

        return r;
    }

    public static void main(String[] args) {
        ArtemisConfig.host = "172.30.30.89:443"; // 平台的ip端口
        ArtemisConfig.appKey = "28868158";  // 密钥appkey
        ArtemisConfig.appSecret = "WEOkGBmfv1AdQXvSRJNI";// 密钥appSecret
        /**
         * STEP2：设置OpenAPI接口的上下文
         */
        final String ARTEMIS_PATH = "/artemis";
        /**
         * STEP3：设置接口的URI地址
         */
        final String previewURLsApi = ARTEMIS_PATH + "/api/resource/v2/encodeDevice/search";
        Map<String, String> path = new HashMap<String, String>(2) {
            {
                put("https://", previewURLsApi);//根据现场环境部署确认是http还是https
            }
        };
        /**
         * STEP4：设置参数提交方式
         */
        String contentType = "application/json;charset=UTF-8";
        /**
         * STEP5：组装请求参数
         */
        JSONObject jsonBody = new JSONObject();
        jsonBody.put("pageNo", 1);
        jsonBody.put("pageSize", 1000);
        String body = jsonBody.toJSONString();
        /**
         * STEP6：调用接口
         */
        String jsonString = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType , null);// post请求application/json类型参数
        System.out.println(body);
        System.out.println(jsonString);
        Result r = null;
        if(jsonString!=null){
            r=  JSON.parseObject(jsonString, Result.class);
        }
        PageHik pageHik = JSON.parseObject(r.getData().toString(), PageHik.class);

        List<Encode> list = new ArrayList<>();
        for(Object o:pageHik.getList()){
            Encode encode = JSON.parseObject(o.toString(), Encode.class);
            list.add(encode);
        }
        System.out.println(JSON.toJSONString(list));
    }
}
